﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace WorldOnFire
{
    public class CSatellite : ABCMovingObject
    {
        #region Satellite Data

        private CBuildable[] m_Buildable;
        private float[] m_fRotationSpeed;

        // Rendering data
        private float[] m_fScale;

        private int m_nSelectedIndex;
        private Vector3 m_vDestination;

        public void MoveSatellite(int _nIndex, Vector3 _vDestination)
        { m_nSelectedIndex = _nIndex; m_vDestination = _vDestination; }

        public void StopSatellite()
        { m_nSelectedIndex = -1; }

        public bool IsSatelliteMoving()
        { return m_nSelectedIndex != -1; }

        const float MINIMUM_SAFE_DISTANCE = 50.0f;

        #endregion Satellite Data

        #region Initialization

        // TODO: KILL
        bool m_bInitialized;

        public override void Initialize(int _nObjectCount)
        {
            // Initialize arrays
            m_Buildable = new CBuildable[_nObjectCount];
            m_fRotationSpeed = new float[_nObjectCount];

            m_fScale = new float[_nObjectCount];

            m_nSelectedIndex = -1;

            // Initialize base members
            base.Initialize(_nObjectCount);

            // Set rendering data
            m_nTechniqueID = (int)CRenderingManager.eObjectTechnique.CELESTIAL_BODY;
            m_bOverlay = true;

            // TODO: DKJAKLDLCAJ WRONG
            for (int iSatellite = 0; iSatellite < _nObjectCount; ++iSatellite)
            {
                m_fRotationSpeed[iSatellite] = s_Ron.NextFloat(-(float)Math.PI / 10.0f, (float)Math.PI / 10.0f);

                m_fRadius[iSatellite] = s_Ron.NextFloat(10.0f, 40.0f);
                m_fScale[iSatellite] = m_fRadius[iSatellite] / 50.0f;

                // TODO: Change. Fix radius thing
                m_Buildable[iSatellite] = new CBuildable();
                m_Buildable[iSatellite].Initialize(m_fRadius[iSatellite]);
            }
        }

        public override void LoadContent()
        {
            // Load the model
            m_eModelID = CRenderingManager.eModelID.CELESTIAL_BODY;

            // Load the texture
            m_eTextureID = CRenderingManager.eTextureID.SATELLITE_1;

            // Load base content
            base.LoadContent();
        }

        #endregion Initialization

        #region Update and Render

        public override void Update(float _fDeltaTime)
        {
            // TODO: FFFFFFFFFUUUUUUUUUUUUUUU
            if (m_bInitialized == false)
            {
                for (int iSatellite = 0; iSatellite < m_nObjectCount; ++iSatellite)
                {
                    m_Buildable[iSatellite].CreateTurret((ABCTurret.eTurretType)0);
                    m_Buildable[iSatellite].CreateTurret((ABCTurret.eTurretType)2);
                    m_Buildable[iSatellite].CreateTurret((ABCTurret.eTurretType)0);
                }
              
                m_bInitialized = true;
            }

            if (m_nSelectedIndex != -1)
            {
                float fSatelliteSpeed = this.GetSpeed(m_nSelectedIndex);
                if (this.IsColliding(m_nSelectedIndex, m_vDestination, 0.25f * fSatelliteSpeed + 2.5f, false) == false)
                {
                    Vector3 vDirection = Vector3.Normalize(m_vDestination
                        - (this.GetProjectedPosition(m_nSelectedIndex, 0.02f * fSatelliteSpeed)));
                    this.ApplyForce(m_nSelectedIndex, 50.0f * vDirection * _fDeltaTime);
                }
                else
                {
                    this.StopSatellite();
                }
            }

            // For each satellite
            for (int iSatellite = 0; iSatellite < m_nObjectCount; ++iSatellite)
            {
                // Update buildable
                m_Buildable[iSatellite].Update(_fDeltaTime, m_mTransform[iSatellite].Translation);

                // Rotate around the Y axis
                Matrix mSpin = Matrix.CreateRotationY(m_fRotationSpeed[iSatellite] * _fDeltaTime);

                Vector3 vTranslation = m_mTransform[iSatellite].Translation;
                m_mTransform[iSatellite].Translation = Vector3.Zero;
                m_mTransform[iSatellite] = m_mTransform[iSatellite] * mSpin;
                m_mTransform[iSatellite].Translation = vTranslation;

                // If no force has been applied
                if (m_vAppliedForce[iSatellite].LengthSquared() == 0.0f)
                {
                    // Slow the fuck down
                    m_vVelocity[iSatellite] -= 2.0f * _fDeltaTime * m_vVelocity[iSatellite];
                }
                else
                {
                    // If we're totally going so fast AH FUCK
                    if (m_vVelocity[iSatellite].LengthSquared() > 40000.0f
                        || Vector3.Dot(Vector3.Normalize(m_vVelocity[iSatellite]),
                        Vector3.Normalize(m_vAppliedForce[iSatellite])) < 0.85f)
                    {
                        // Slow the fuck down
                        m_vVelocity[iSatellite] -= 1.0f * _fDeltaTime * m_vVelocity[iSatellite];
                    }
                }
            }

            // For each satellite
            for (int iSatellite = 0; iSatellite < m_nObjectCount; ++iSatellite)
            {
                // For every other satellite
                for (int iOtherSatellite = iSatellite + 1; iOtherSatellite < m_nObjectCount; ++iOtherSatellite)
                {
                    // Find the vector between
                    Vector3 vBetween = this.GetPosition(iOtherSatellite) - this.GetPosition(iSatellite);

                    // Find the combined radius
                    float fCombinedRadius = m_fRadius[iSatellite] + m_fRadius[iOtherSatellite];

                    // If the distance between is less than the minimum safe distance added to the radius
                    if (vBetween.LengthSquared() < (MINIMUM_SAFE_DISTANCE + fCombinedRadius)
                        * (MINIMUM_SAFE_DISTANCE + fCombinedRadius))
                    {
                        // Correct each satellite's position
                        float fCorrectionDistance = vBetween.Length();
                        vBetween /= fCorrectionDistance;
                        fCorrectionDistance = MINIMUM_SAFE_DISTANCE + fCombinedRadius - fCorrectionDistance;

                        m_mTransform[iSatellite].Translation -= 0.5f * fCorrectionDistance * vBetween;
                        m_mTransform[iOtherSatellite].Translation += 0.5f * fCorrectionDistance * vBetween;

                        // Apply a force to each satellite
                        this.ApplyForce(iOtherSatellite, 0.5f * m_fMass * vBetween);
                        this.ApplyForce(iSatellite, -0.5f * m_fMass * vBetween);
                    }
                }
            }

            // For each enemy type
            for (int iEnemyType = 0; iEnemyType < (int)ABCEnemy.eEnemyType.COUNT; ++iEnemyType)
            {
                // Store the enemy locally
                ABCEnemy Enemy = s_ObjectManager.GetEnemy((ABCEnemy.eEnemyType)iEnemyType);

                // For every satellite
                for (int iSatellite = 0; iSatellite < m_nObjectCount; ++iSatellite)
                {
                    // For every enemy
                    for (int iEnemy = 0; iEnemy < Enemy.GetObjectCount(); ++iEnemy)
                    {
                        // Find the vector between
                        Vector3 vBetween = Enemy.GetPosition(iEnemy) - this.GetPosition(iSatellite);

                        // If the distance between is less than the minimum safe distance added to the radius
                        if (vBetween.LengthSquared() < (MINIMUM_SAFE_DISTANCE + m_fRadius[iSatellite])
                            * (MINIMUM_SAFE_DISTANCE + m_fRadius[iSatellite]))
                        {
                            // Apply a force to each satellite
                            vBetween.Normalize();
                            vBetween += Enemy.GetOrbitVector(iEnemy);
                            vBetween.Normalize();
                            Enemy.ApplyForce(iEnemy, 500.0f * Enemy.GetMass() * _fDeltaTime * vBetween);
                        }
                    }
                }
            }

                // Update base members
                base.Update(_fDeltaTime);
        }

        public override bool RespondToCollision(int _nIndex, ABCObject _Object, int _nObjectIndex)
        {
            return true;
        }

        protected override void CopyRenderingTransforms()
        {
            // Loop through each index for rendering
            for (int iRenderingIndex = 0; iRenderingIndex < m_nObjectsActive; ++iRenderingIndex)
            {
                int nIndex = m_ActiveIndexList[iRenderingIndex];

                // Copy the transform into the rendering transform array
                m_mRenderingTransforms[iRenderingIndex] = m_mTransform[nIndex];

                // Scale the transform
                Matrix mScale = Matrix.CreateScale(m_fScale[nIndex]);
                m_mRenderingTransforms[iRenderingIndex].Translation = Vector3.Zero;
                m_mRenderingTransforms[iRenderingIndex] = mScale * m_mRenderingTransforms[iRenderingIndex];
                m_mRenderingTransforms[iRenderingIndex].Translation = m_mTransform[nIndex].Translation;
            }
        }

        #endregion Update and Render
    }
}
